package com.qyer.commons.concurrent;

import static org.apache.commons.lang3.builder.ToStringStyle.SHORT_PREFIX_STYLE;

import com.google.common.collect.Lists;
import com.qyer.commons.concurrent.assemblingline.AssemblingLineException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.util.List;

/**
 * User: Z J Wu Date: 2016/05/11 Time: 11:51 Package: com.qyer.commons.concurrent
 */
public class ArrayListBulk<T> implements PoisonPill<ArrayListBulk<T>> {

  public static ArrayListBulk PILL_MAKER = new ArrayListBulk<>();

  private int capacity;
  private List<T> list;

  private ArrayListBulk() {
    this.capacity = 0;
  }

  public static <T> ArrayListBulk<T> newArrayListBulkByCapacity(int capacity) {
    if (capacity <= 0) {
      throw new IllegalArgumentException("Capacity must be greater than 0.");
    }
    ArrayListBulk bulk = new ArrayListBulk();
    bulk.capacity = capacity;
    bulk.list = Lists.newArrayListWithCapacity(capacity);
    return bulk;
  }

  public List<T> getList() {
    return this.list;
  }

  public int size() {
    return this.list.size();
  }

  public int capacity() {
    return this.capacity;
  }

  public boolean isFull() {
    return this.list.size() == this.capacity;
  }

  public void add(T t) {
    if (t == null) {
      return;
    }
    if (isFull()) {
      throw new RuntimeException("Current bulk is full.");
    }
    this.list.add(t);
  }

  public boolean isEmpty() {
    return CollectionUtils.isEmpty(this.list);
  }

  public void addAll(List<T> src) throws AssemblingLineException {
    if (CollectionUtils.isEmpty(src)) {
      return;
    }
    if (list.size() + src.size() > capacity) {
      throw new AssemblingLineException(
        "Bulk is full, cannot insert a list of " + src.size() + " into bulk(" + size() + ")");
    }
    list.addAll(src);
  }

  @Override
  public String toString() {
    return new ToStringBuilder(this, SHORT_PREFIX_STYLE).append("capacity", capacity)
                                                        .append("list", list).toString();
  }

  @Override
  public boolean isPill() {
    return this.capacity == 0;
  }

  @Override
  public ArrayListBulk<T> createPill() {
    return new ArrayListBulk<>();
  }

  public int remain() {
    return capacity - list.size();
  }

  public List<T> cut(int cnt) {
    if (cnt <= 0) {
      return null;
    }
    List<T> subList;
    if (cnt >= list.size()) {
      subList = list;
      list = Lists.newArrayListWithCapacity(capacity);
      return subList;
    }
    subList = list.subList(0, cnt);
    list = Lists.newArrayList(list.subList(cnt, list.size()));
    return subList;
  }

}
